﻿using System;
using System.Drawing;
using System.Windows.Forms;
using System.IO;

namespace BugSnapper
{


    public partial class GetSelectionArea : Form
    {
        #region:::::::::::::::::::::::::::::::::::::::::::Form level declarations:::::::::::::::::::::::::::::::::::::::::::
        private delegate void GenericWindowsEventsHandler<TArgs>(object sender, TArgs e);
        private Logger Logger { get; set; }
        public enum CursPos : int
        {
            WithinSelectionArea = 0,
            OutsideSelectionArea,
            TopLine,
            BottomLine,
            LeftLine,
            RightLine,
            TopLeft,
            TopRight,
            BottomLeft,
            BottomRight
        }

        public enum ClickAction : int
        {
            NoClick = 0,
            Dragging,
            Outside,
            TopSizing,
            BottomSizing,
            LeftSizing,
            TopLeftSizing,
            BottomLeftSizing,
            RightSizing,
            TopRightSizing,
            BottomRightSizing
        }

        public ClickAction CurrentAction;
        public bool LeftButtonDown = false;
        public bool RectangleDrawn = false;
        public bool ReadyToDrag = false;
        string ScreenPath;

        public Point ClickPoint = new Point();
        public Point CurrentTopLeft = new Point();
        public Point CurrentBottomRight = new Point();
        public Point DragClickRelative = new Point();


        public int RectangleHeight = new int();
        public int RectangleWidth = new int();

        Graphics g;
        Pen MyPen = new Pen(Color.Black, 1);
        SolidBrush TransparentBrush = new SolidBrush(Color.White);
        Pen EraserPen = new Pen(Color.FromArgb(255, 255, 192), 1);
        SolidBrush eraserBrush = new SolidBrush(Color.FromArgb(255, 255, 192));

        private delegate void OnMouseClickHandler(MouseEventArgs e);
        protected override void OnMouseClick(MouseEventArgs e)
        {
            if (!IsDisposed)
            {
                if (!InvokeRequired)
                {
                    try
                    {
                        if (e.Button == MouseButtons.Right)
                        {
                            e = null;
                        }
                        base.OnMouseClick(e);
                    }
                    catch (Exception ex)
                    {
                        this.Logger.ProcessError(ex);
                    }
                }
                else
                {
                    Invoke(new OnMouseClickHandler(OnMouseClick), e);
                }
            }
        }

        private Form m_InstanceRef = null;
        public Form InstanceRef
        {
            get
            {
                return m_InstanceRef;
            }
            set
            {
                m_InstanceRef = value;
            }
        }

        #endregion

        #region:::::::::::::::::::::::::::::::::::::::::::Mouse Event Handlers & Drawing Initialization:::::::::::::::::::::::::::::::::::::::::::
        public GetSelectionArea()
        {

            InitializeComponent();
            this.Logger = new Logger();
            this.MouseDown += new MouseEventHandler(mouse_Click);
            this.MouseDoubleClick += new MouseEventHandler(mouse_DClick);
            this.MouseUp += new MouseEventHandler(mouse_Up);
            this.MouseMove += new MouseEventHandler(mouse_Move);
            //MyPen.DashStyle = System.Drawing.Drawing2D.DashStyle.Dot;
            g = this.CreateGraphics();
        }
        #endregion


        #region:::::::::::::::::::::::::::::::::::::::::::Mouse Buttons:::::::::::::::::::::::::::::::::::::::::::
        private void mouse_DClick(object sender, MouseEventArgs e)
        {
            if (!IsDisposed)
            {
                if (!InvokeRequired)
                {
                    try
                    {
                        if (RectangleDrawn)// && (CursorPosition() == CursPos.WithinSelectionArea || CursorPosition() == CursPos.OutsideSelectionArea))
                        {
                            this.StartPoint = new Point(CurrentTopLeft.X, CurrentTopLeft.Y);
                            this.RectangleBounds = new Rectangle(CurrentTopLeft.X, CurrentTopLeft.Y, CurrentBottomRight.X - CurrentTopLeft.X, CurrentBottomRight.Y - CurrentTopLeft.Y);
                            this.Close();
                        }
                    }
                    catch (Exception ex)
                    {
                        this.Logger.ProcessError(ex);
                    }
                }
                else
                {
                    Invoke(new GenericWindowsEventsHandler<MouseEventArgs>(mouse_DClick), sender, e);
                }
            }
        }
        public Point StartPoint { get; set; }
        public Rectangle RectangleBounds { get; set; }

        private void mouse_Click(object sender, MouseEventArgs e)
        {
            if (!IsDisposed)
            {
                if (!InvokeRequired)
                {
                    try
                    {
                        if (e.Button == MouseButtons.Left)
                        {
                            SetClickAction();
                            LeftButtonDown = true;
                            ClickPoint = new Point(System.Windows.Forms.Control.MousePosition.X, System.Windows.Forms.Control.MousePosition.Y);

                            if (RectangleDrawn)
                            {
                                RectangleHeight = CurrentBottomRight.Y - CurrentTopLeft.Y;
                                RectangleWidth = CurrentBottomRight.X - CurrentTopLeft.X;
                                DragClickRelative.X = Cursor.Position.X - CurrentTopLeft.X;
                                DragClickRelative.Y = Cursor.Position.Y - CurrentTopLeft.Y;
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                        this.Logger.ProcessError(ex);
                    }
                }
                else
                {
                    Invoke(new GenericWindowsEventsHandler<MouseEventArgs>(mouse_Click), sender, e);
                }
            }
        }

        private void mouse_Up(object sender, MouseEventArgs e)
        {
            if (!IsDisposed)
            {
                if (!InvokeRequired)
                {
                    try
                    {
                        RectangleDrawn = true;
                        LeftButtonDown = false;
                        CurrentAction = ClickAction.NoClick;
                        this.mouse_DClick(this, e);
                    }
                    catch (Exception ex)
                    {
                        this.Logger.ProcessError(ex);
                    }
                }
                else
                {
                    Invoke(new GenericWindowsEventsHandler<MouseEventArgs>(mouse_Up), sender, e);
                }
            }
        }
        #endregion



        private void mouse_Move(object sender, MouseEventArgs e)
        {
            if (!IsDisposed)
            {
                if (!InvokeRequired)
                {
                    try
                    {
                        if (LeftButtonDown && !RectangleDrawn)
                        {
                            DrawSelection();
                        }

                        if (RectangleDrawn)
                        {
                            CursorPosition();

                            if (CurrentAction == ClickAction.Dragging)
                            {
                                DragSelection();
                            }

                            if (CurrentAction != ClickAction.Dragging && CurrentAction != ClickAction.Outside)
                            {
                                ResizeSelection();
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                        this.Logger.ProcessError(ex);
                    }
                }
                else
                {
                    Invoke(new GenericWindowsEventsHandler<MouseEventArgs>(mouse_Move), sender, e);
                }
            }
        }

        private CursPos CursorPosition()
        {
            if (((Cursor.Position.X > CurrentTopLeft.X - 10 && Cursor.Position.X < CurrentTopLeft.X + 10)) && ((Cursor.Position.Y > CurrentTopLeft.Y + 10) && (Cursor.Position.Y < CurrentBottomRight.Y - 10)))
            {
                this.Cursor = Cursors.SizeWE;
                return CursPos.LeftLine;
            }
            if (((Cursor.Position.X >= CurrentTopLeft.X - 10 && Cursor.Position.X <= CurrentTopLeft.X + 10)) && ((Cursor.Position.Y >= CurrentTopLeft.Y - 10) && (Cursor.Position.Y <= CurrentTopLeft.Y + 10)))
            {
                this.Cursor = Cursors.SizeNWSE;
                return CursPos.TopLeft;
            }
            if (((Cursor.Position.X >= CurrentTopLeft.X - 10 && Cursor.Position.X <= CurrentTopLeft.X + 10)) && ((Cursor.Position.Y >= CurrentBottomRight.Y - 10) && (Cursor.Position.Y <= CurrentBottomRight.Y + 10)))
            {
                this.Cursor = Cursors.SizeNESW;
                return CursPos.BottomLeft;
            }
            if (((Cursor.Position.X > CurrentBottomRight.X - 10 && Cursor.Position.X < CurrentBottomRight.X + 10)) && ((Cursor.Position.Y > CurrentTopLeft.Y + 10) && (Cursor.Position.Y < CurrentBottomRight.Y - 10)))
            {
                this.Cursor = Cursors.SizeWE;
                return CursPos.RightLine;
            }
            if (((Cursor.Position.X >= CurrentBottomRight.X - 10 && Cursor.Position.X <= CurrentBottomRight.X + 10)) && ((Cursor.Position.Y >= CurrentTopLeft.Y - 10) && (Cursor.Position.Y <= CurrentTopLeft.Y + 10)))
            {
                this.Cursor = Cursors.SizeNESW;
                return CursPos.TopRight;
            }
            if (((Cursor.Position.X >= CurrentBottomRight.X - 10 && Cursor.Position.X <= CurrentBottomRight.X + 10)) && ((Cursor.Position.Y >= CurrentBottomRight.Y - 10) && (Cursor.Position.Y <= CurrentBottomRight.Y + 10)))
            {
                this.Cursor = Cursors.SizeNWSE;
                return CursPos.BottomRight;
            }
            if (((Cursor.Position.Y > CurrentTopLeft.Y - 10) && (Cursor.Position.Y < CurrentTopLeft.Y + 10)) && ((Cursor.Position.X > CurrentTopLeft.X + 10 && Cursor.Position.X < CurrentBottomRight.X - 10)))
            {
                this.Cursor = Cursors.SizeNS;
                return CursPos.TopLine;
            }
            if (((Cursor.Position.Y > CurrentBottomRight.Y - 10) && (Cursor.Position.Y < CurrentBottomRight.Y + 10)) && ((Cursor.Position.X > CurrentTopLeft.X + 10 && Cursor.Position.X < CurrentBottomRight.X - 10)))
            {
                this.Cursor = Cursors.SizeNS;
                return CursPos.BottomLine;
            }
            if (
                (Cursor.Position.X >= CurrentTopLeft.X + 10 && Cursor.Position.X <= CurrentBottomRight.X - 10) && (Cursor.Position.Y >= CurrentTopLeft.Y + 10 && Cursor.Position.Y <= CurrentBottomRight.Y - 10))
            {
                this.Cursor = Cursors.Hand;
                return CursPos.WithinSelectionArea;
            }
            this.Cursor = Cursors.No;
            return CursPos.OutsideSelectionArea;
        }

        private void SetClickAction()
        {
            try
            {
                if (CursorPosition() == CursPos.BottomLine)
                {
                    CurrentAction = ClickAction.BottomSizing;
                }
                if (CursorPosition() == CursPos.TopLine)
                {
                    CurrentAction = ClickAction.TopSizing;
                }
                if (CursorPosition() == CursPos.LeftLine)
                {
                    CurrentAction = ClickAction.LeftSizing;
                }
                if (CursorPosition() == CursPos.TopLeft)
                {
                    CurrentAction = ClickAction.TopLeftSizing;
                }
                if (CursorPosition() == CursPos.BottomLeft)
                {
                    CurrentAction = ClickAction.BottomLeftSizing;
                }
                if (CursorPosition() == CursPos.RightLine)
                {
                    CurrentAction = ClickAction.RightSizing;
                }
                if (CursorPosition() == CursPos.TopRight)
                {
                    CurrentAction = ClickAction.TopRightSizing;
                }
                if (CursorPosition() == CursPos.BottomRight)
                {
                    CurrentAction = ClickAction.BottomRightSizing;
                }
                if (CursorPosition() == CursPos.WithinSelectionArea)
                {
                    CurrentAction = ClickAction.Dragging;
                }
                if (CursorPosition() == CursPos.OutsideSelectionArea)
                {
                    CurrentAction = ClickAction.Outside;
                }
            }
            catch (Exception ex)
            {
                this.Logger.ProcessError(ex);
            }
        }

        private void ResizeSelection()
        {
            try
            {
                if (CurrentAction == ClickAction.LeftSizing)
                {
                    if (Cursor.Position.X < CurrentBottomRight.X - 10)
                    {
                        //Erase the previous rectangle
                        g.DrawRectangle(EraserPen, CurrentTopLeft.X, CurrentTopLeft.Y, RectangleWidth, RectangleHeight);
                        CurrentTopLeft.X = Cursor.Position.X;
                        RectangleWidth = CurrentBottomRight.X - CurrentTopLeft.X;
                        g.DrawRectangle(MyPen, CurrentTopLeft.X, CurrentTopLeft.Y, RectangleWidth, RectangleHeight);
                    }
                }
                if (CurrentAction == ClickAction.TopLeftSizing)
                {
                    if (Cursor.Position.X < CurrentBottomRight.X - 10 && Cursor.Position.Y < CurrentBottomRight.Y - 10)
                    {
                        //Erase the previous rectangle
                        g.DrawRectangle(EraserPen, CurrentTopLeft.X, CurrentTopLeft.Y, RectangleWidth, RectangleHeight);
                        CurrentTopLeft.X = Cursor.Position.X;
                        CurrentTopLeft.Y = Cursor.Position.Y;
                        RectangleWidth = CurrentBottomRight.X - CurrentTopLeft.X;
                        RectangleHeight = CurrentBottomRight.Y - CurrentTopLeft.Y;
                        g.DrawRectangle(MyPen, CurrentTopLeft.X, CurrentTopLeft.Y, RectangleWidth, RectangleHeight);
                    }
                }
                if (CurrentAction == ClickAction.BottomLeftSizing)
                {
                    if (Cursor.Position.X < CurrentBottomRight.X - 10 && Cursor.Position.Y > CurrentTopLeft.Y + 10)
                    {
                        //Erase the previous rectangle
                        g.DrawRectangle(EraserPen, CurrentTopLeft.X, CurrentTopLeft.Y, RectangleWidth, RectangleHeight);
                        CurrentTopLeft.X = Cursor.Position.X;
                        CurrentBottomRight.Y = Cursor.Position.Y;
                        RectangleWidth = CurrentBottomRight.X - CurrentTopLeft.X;
                        RectangleHeight = CurrentBottomRight.Y - CurrentTopLeft.Y;
                        g.DrawRectangle(MyPen, CurrentTopLeft.X, CurrentTopLeft.Y, RectangleWidth, RectangleHeight);
                    }
                }
                if (CurrentAction == ClickAction.RightSizing)
                {
                    if (Cursor.Position.X > CurrentTopLeft.X + 10)
                    {
                        //Erase the previous rectangle
                        g.DrawRectangle(EraserPen, CurrentTopLeft.X, CurrentTopLeft.Y, RectangleWidth, RectangleHeight);
                        CurrentBottomRight.X = Cursor.Position.X;
                        RectangleWidth = CurrentBottomRight.X - CurrentTopLeft.X;
                        g.DrawRectangle(MyPen, CurrentTopLeft.X, CurrentTopLeft.Y, RectangleWidth, RectangleHeight);
                    }
                }
                if (CurrentAction == ClickAction.TopRightSizing)
                {
                    if (Cursor.Position.X > CurrentTopLeft.X + 10 && Cursor.Position.Y < CurrentBottomRight.Y - 10)
                    {
                        //Erase the previous rectangle
                        g.DrawRectangle(EraserPen, CurrentTopLeft.X, CurrentTopLeft.Y, RectangleWidth, RectangleHeight);
                        CurrentBottomRight.X = Cursor.Position.X;
                        CurrentTopLeft.Y = Cursor.Position.Y;
                        RectangleWidth = CurrentBottomRight.X - CurrentTopLeft.X;
                        RectangleHeight = CurrentBottomRight.Y - CurrentTopLeft.Y;
                        g.DrawRectangle(MyPen, CurrentTopLeft.X, CurrentTopLeft.Y, RectangleWidth, RectangleHeight);
                    }
                }
                if (CurrentAction == ClickAction.BottomRightSizing)
                {
                    if (Cursor.Position.X > CurrentTopLeft.X + 10 && Cursor.Position.Y > CurrentTopLeft.Y + 10)
                    {
                        //Erase the previous rectangle
                        g.DrawRectangle(EraserPen, CurrentTopLeft.X, CurrentTopLeft.Y, RectangleWidth, RectangleHeight);
                        CurrentBottomRight.X = Cursor.Position.X;
                        CurrentBottomRight.Y = Cursor.Position.Y;
                        RectangleWidth = CurrentBottomRight.X - CurrentTopLeft.X;
                        RectangleHeight = CurrentBottomRight.Y - CurrentTopLeft.Y;
                        g.DrawRectangle(MyPen, CurrentTopLeft.X, CurrentTopLeft.Y, RectangleWidth, RectangleHeight);
                    }
                }
                if (CurrentAction == ClickAction.TopSizing)
                {
                    if (Cursor.Position.Y < CurrentBottomRight.Y - 10)
                    {
                        //Erase the previous rectangle
                        g.DrawRectangle(EraserPen, CurrentTopLeft.X, CurrentTopLeft.Y, RectangleWidth, RectangleHeight);
                        CurrentTopLeft.Y = Cursor.Position.Y;
                        RectangleHeight = CurrentBottomRight.Y - CurrentTopLeft.Y;
                        g.DrawRectangle(MyPen, CurrentTopLeft.X, CurrentTopLeft.Y, RectangleWidth, RectangleHeight);
                    }
                }
                if (CurrentAction == ClickAction.BottomSizing)
                {
                    if (Cursor.Position.Y > CurrentTopLeft.Y + 10)
                    {
                        //Erase the previous rectangle
                        g.DrawRectangle(EraserPen, CurrentTopLeft.X, CurrentTopLeft.Y, RectangleWidth, RectangleHeight);
                        CurrentBottomRight.Y = Cursor.Position.Y;
                        RectangleHeight = CurrentBottomRight.Y - CurrentTopLeft.Y;
                        g.DrawRectangle(MyPen, CurrentTopLeft.X, CurrentTopLeft.Y, RectangleWidth, RectangleHeight);
                    }
                }
            }
            catch (Exception ex)
            {
                this.Logger.ProcessError(ex);
            }
        }

        private void DragSelection()
        {
            try
            {
                //Ensure that the rectangle stays within the bounds of the screen

                //Erase the previous rectangle
                //g.FillRectangle(eraserBrush, CurrentTopLeft.X, CurrentTopLeft.Y, CurrentBottomRight.X - CurrentTopLeft.X, CurrentBottomRight.Y - CurrentTopLeft.Y);
                g.DrawRectangle(EraserPen, CurrentTopLeft.X, CurrentTopLeft.Y, RectangleWidth, RectangleHeight);

                if (Cursor.Position.X - DragClickRelative.X > 0 && Cursor.Position.X - DragClickRelative.X + RectangleWidth < System.Windows.Forms.Screen.PrimaryScreen.Bounds.Width)
                {
                    CurrentTopLeft.X = Cursor.Position.X - DragClickRelative.X;
                    CurrentBottomRight.X = CurrentTopLeft.X + RectangleWidth;
                }
                else
                    //Selection area has reached the right side of the screen
                    if (Cursor.Position.X - DragClickRelative.X > 0)
                    {
                        CurrentTopLeft.X = System.Windows.Forms.Screen.PrimaryScreen.Bounds.Width - RectangleWidth;
                        CurrentBottomRight.X = CurrentTopLeft.X + RectangleWidth;
                    }
                    //Selection area has reached the left side of the screen
                    else
                    {
                        CurrentTopLeft.X = 0;
                        CurrentBottomRight.X = CurrentTopLeft.X + RectangleWidth;
                    }

                if (Cursor.Position.Y - DragClickRelative.Y > 0 && Cursor.Position.Y - DragClickRelative.Y + RectangleHeight < System.Windows.Forms.Screen.PrimaryScreen.Bounds.Height)
                {
                    CurrentTopLeft.Y = Cursor.Position.Y - DragClickRelative.Y;
                    CurrentBottomRight.Y = CurrentTopLeft.Y + RectangleHeight;
                }
                else
                    //Selection area has reached the bottom of the screen
                    if (Cursor.Position.Y - DragClickRelative.Y > 0)
                    {
                        CurrentTopLeft.Y = System.Windows.Forms.Screen.PrimaryScreen.Bounds.Height - RectangleHeight;
                        CurrentBottomRight.Y = CurrentTopLeft.Y + RectangleHeight;
                    }
                    //Selection area has reached the top of the screen
                    else
                    {
                        CurrentTopLeft.Y = 0;
                        CurrentBottomRight.Y = CurrentTopLeft.Y + RectangleHeight;
                    }

                //Draw a new rectangle
                //g.FillRectangle(TransparentBrush, CurrentTopLeft.X, CurrentTopLeft.Y, CurrentBottomRight.X - CurrentTopLeft.X, CurrentBottomRight.Y - CurrentTopLeft.Y);
                g.DrawRectangle(MyPen, CurrentTopLeft.X, CurrentTopLeft.Y, RectangleWidth, RectangleHeight);
            }
            catch (Exception ex)
            {
                this.Logger.ProcessError(ex);
            }
        }

        private void DrawSelection()
        {
            try
            {
                this.Cursor = Cursors.Cross;

                //Erase the previous rectangle
                //g.FillRectangle(eraserBrush, CurrentTopLeft.X, CurrentTopLeft.Y, CurrentBottomRight.X - CurrentTopLeft.X, CurrentBottomRight.Y - CurrentTopLeft.Y);
                g.DrawRectangle(EraserPen, CurrentTopLeft.X, CurrentTopLeft.Y, CurrentBottomRight.X - CurrentTopLeft.X, CurrentBottomRight.Y - CurrentTopLeft.Y);

                //Calculate X Coordinates
                if (Cursor.Position.X < ClickPoint.X)
                {
                    CurrentTopLeft.X = Cursor.Position.X;
                    CurrentBottomRight.X = ClickPoint.X;
                }
                else
                {
                    CurrentTopLeft.X = ClickPoint.X;
                    CurrentBottomRight.X = Cursor.Position.X;
                }

                //Calculate Y Coordinates
                if (Cursor.Position.Y < ClickPoint.Y)
                {
                    CurrentTopLeft.Y = Cursor.Position.Y;
                    CurrentBottomRight.Y = ClickPoint.Y;
                }
                else
                {
                    CurrentTopLeft.Y = ClickPoint.Y;
                    CurrentBottomRight.Y = Cursor.Position.Y;
                }

                //Draw a new rectangle
                //g.FillRectangle(TransparentBrush, CurrentTopLeft.X, CurrentTopLeft.Y, CurrentBottomRight.X - CurrentTopLeft.X, CurrentBottomRight.Y - CurrentTopLeft.Y);
                g.DrawRectangle(MyPen, CurrentTopLeft.X, CurrentTopLeft.Y, CurrentBottomRight.X - CurrentTopLeft.X, CurrentBottomRight.Y - CurrentTopLeft.Y);

            }
            catch (Exception ex)
            {

                this.Logger.ProcessError(ex);
            }
        }
    }
}